package com.app.service;

import com.app.model.cache.RedisKeys;
import com.app.model.main.SearchRecord;
import com.app.model.main.User;
import com.app.model.main.UserInfo;
import com.app.model.main.UserSearchRecord;
import com.app.model.position.Position;
import com.app.model.position.PositionFlag;
import com.app.model.position.UserNearBy;
import com.app.model.response.RecommendUserResponseBody;
import com.app.model.response.RetCode;
import com.app.model.response.RetStatus;
import com.app.model.solr.SolrFlag;
import com.app.model.util.CommonFlag;
import com.app.model.util.UserWithScore;
import com.app.repository.interfaces.*;
import com.app.service.utils.SearchUtil;
import com.app.support.utils.RedisUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.log4j.Logger;
import org.apache.solr.common.SolrDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.metrics.export.MetricExportProperties;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Created by Lichaojie on 2017/3/24. It's a beautiful day.
 */
@Service
public class SearchService {

    private final Logger logger = Logger.getLogger(SearchService.class);

    @Autowired
    private SearchRecordMapper searchRecordMapper;
    @Autowired
    private ResponseService responseService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private SearchUtil searchUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private ImageMapper imageMapper;
    @Autowired
    private PositionService positionService;
    @Autowired
    private UserSearchRecordMapper userSearchRecordMapper;
    @Autowired
    private SolrService solrService;


    public boolean addSearchRecord(String keyword,String label,String time,byte type,long userId){
        SearchRecord searchRecord = new SearchRecord();
        searchRecord.setKeyword(keyword)
                .setLabel(label)
                .setTime(time)
                .setType(type);

        if(searchRecordMapper.insertSelective(searchRecord) == 1){
            SearchRecord searchRecord1 = searchRecordMapper.selectByParam(keyword,label,time,type);
            UserSearchRecord userSearchRecord = new UserSearchRecord();
            userSearchRecord.setUserId(userId)
                    .setSearchId(searchRecord1.getId())
                    .setTime(searchRecord1.getTime());
            if(userSearchRecordMapper.insertSelective(userSearchRecord) == 1){
                return true;
            }else {
                return false;
            }
        }else {
            return false;
        }
    }

    public RetStatus doSearch(String parameter){
        ObjectMapper objectMapper = new ObjectMapper();
        Map paraMap = null;
        try{
            paraMap = objectMapper.readValue(parameter,Map.class);
        }catch (IOException e){
            e.printStackTrace();
            return responseService.doResponse(204);
        }

        int iid = (int)paraMap.get("userId");
        long userId = (long)iid;
        String keywords = (String)paraMap.get("keywords");
        String labelStr = (String)paraMap.get("label");
        int page = (int)paraMap.get("page");
        int number = (int)paraMap.get("number");

        String queryString = keywords;
        String[] strings = labelStr.split(",");
        for (String s : strings){
            queryString += (" " + s);
        }

        //添加搜索记录
        addSearchRecord(keywords,labelStr,Long.toString(System.currentTimeMillis()), CommonFlag.USER,userId);

        if(page == 0){
            //进行用户名匹配
            List resultList = solrService.query(queryString, SolrFlag.USER,0,4);
            List<Long> idList = new ArrayList<>();
            if(resultList.size() > 0){
                for (Object object : resultList){
                    SolrDocument solrDocument = (SolrDocument)object;
                    long tUserId = Long.parseLong((String)solrDocument.getFieldValue("id"));
                    if(tUserId != userId && idList.size() < 3){
                        idList.add(tUserId);
                    }
                }
            }


            List<User> userList = userMapper.getAllUser();
            List<UserWithScore> userWithScoreList = new ArrayList<>();
            for (User user : userList){
                long id = user.getId();
                if(id != userId && !idList.contains(id)){//去掉发出动作的用户本身,去掉前几个按用户名匹配的用户
                    UserWithScore userWithScore = new UserWithScore();

                    double score1 = searchUtil.getActivity(id);
                    double score2 = searchUtil.getSuitability(queryString, id);
                    double score3 = searchUtil.getAuthoritative(id);

                    userWithScore.setUserId(id)
                            .setScore(score1 + score2 + score3);
                    userWithScoreList.add(userWithScore);
                }
            }

            //按得分升序排序
            Collections.sort(userWithScoreList);
            //翻转之后变为得分降序
            Collections.reverse(userWithScoreList);

            //将用户名匹配的结果放入最终的结果集中
            int i = 0;
            for (long id : idList){
                UserWithScore userWithScore = new UserWithScore();
                userWithScore.setUserId(id)
                        .setScore(-1);
                userWithScoreList.add(i++,userWithScore);
            }

            String key = RedisKeys.SEARCH_USER_LIST + Long.toString(userId);
            if(redisUtil.exists(key)){
                redisUtil.remove(key);
            }
            redisUtil.set(key,userWithScoreList);
        }

        List<UserWithScore> list = redisUtil.get(RedisKeys.SEARCH_USER_LIST + Long.toString(userId));
        if(list == null){
            return responseService.doResponse(200);
        }else {
            long start = page * number > list.size() ? list.size() : page * number ;
            long end = page * number + number > list.size() ? list.size() : page * number + number ;
            List<RecommendUserResponseBody> userResponseBodyList = new ArrayList<>();
            for (long i = start;i < end; i ++){
                UserWithScore userWithScore = list.get((int)i);
                UserInfo userInfo = userInfoMapper.selectByPrimaryKey(userWithScore.getUserId());

                logger.info("userId : " + userWithScore.getUserId() + "     score : " + userWithScore.getScore());

                RecommendUserResponseBody recommendUserResponseBody = new RecommendUserResponseBody();
                recommendUserResponseBody.setUserId(userInfo.getId())
                        .setNickName(userInfo.getNickName())
                        .setLabel(userInfo.getLabel())
                        .setIntroduction(userInfo.getIntroduction())
                        .setAvator(imageMapper.selectByPrimaryKey(userInfo.getAvator()).getOrigin());

                userResponseBodyList.add(recommendUserResponseBody);
            }

            if(userResponseBodyList.size() == 0 && page == 0){
                return responseService.doResponse(214);
            }else if(userResponseBodyList.size() == 0 && page != 0){
                return responseService.doResponse(216);
            }else{
                RetStatus retStatus = new RetStatus();
                retStatus.setCode(100)
                        .setMessage(RetCode.getMessage(100))
                        .setBody(userResponseBodyList);
                return retStatus;
            }
        }

    }

    public RetStatus doSearchWithDistance(String parameter){
        ObjectMapper objectMapper = new ObjectMapper();
        Map paraMap = null;
        try{
            paraMap = objectMapper.readValue(parameter,Map.class);
        }catch (IOException e){
            e.printStackTrace();
            return responseService.doResponse(204);
        }

        int id = (int)paraMap.get("userId");
        long userId = (long)id;
        String keywords = (String)paraMap.get("keywords");
        String labelStr = (String)paraMap.get("label");
        int page = (int)paraMap.get("page");
        int number = (int)paraMap.get("number");

        if(page == 0){
            //获取当前搜索结果（不包含距离）
            List<UserWithScore> list = redisUtil.get(RedisKeys.SEARCH_USER_LIST + Long.toString(userId));

            //获取所有附近用户
            List<UserNearBy> userNearByList = new ArrayList<>();
            List<Long> idList = new ArrayList<>();

            UserInfo userInfoI = userInfoMapper.selectByPrimaryKey(userId);
            String[] strArrayI = userInfoI.getPosition().split(",");
            Position myPosition = new Position(Double.parseDouble(strArrayI[0]),Double.parseDouble(strArrayI[1]));

            List<User> userList = userMapper.getAllUser();
            for (User user : userList){
                UserInfo userInfo = userInfoMapper.selectByPrimaryKey(user.getId());
                String pStr = userInfo.getPosition();
                if(pStr.equals("")){
                    continue;
                }
                String[] strArray = pStr.split(",");
                Position tPosition = new Position(Double.parseDouble(strArray[0]),Double.parseDouble(strArray[1]));
                double distance = positionService.getDistance(myPosition, tPosition);
                if(distance - PositionFlag.MAX_DISTANCE < 0){//找到所有在附近的用户
                    UserNearBy userNearBy = new UserNearBy();
                    userNearBy.setUserId(user.getId())
                            .setDistance(distance)
                            .setAvator(imageMapper.selectByPrimaryKey(userInfo.getAvator()).getOrigin())
                            .setNickName(userInfo.getNickName())
                            .setLabel(userInfo.getLabel())
                            .setIntroduction(userInfo.getIntroduction());
                    userNearByList.add(userNearBy);
                    idList.add(user.getId());
                }
            }

            //去除用户本身
            idList.remove(new Long(userId));

            //12km范围内得分超过120的用户ID
            List<Long> scoreList1 = new ArrayList<>();
            //12km范围内得分不超过120的用户ID
            List<Long> scoreList2 = new ArrayList<>();

            for (UserWithScore userWithScore : list){
                long tid = userWithScore.getUserId();
                double tscore = userWithScore.getScore();
                if(idList.contains(new Long(tid))){
                    if(tscore - 120.0 > 0){
                        scoreList1.add(tid);
                    }else {
                        scoreList2.add(tid);
                    }
                }
            }

            //12km内得分超过120的用户信息
            List<UserNearBy> userNearByList1 = new ArrayList<>();
            //12km内得分不超过120的用户信息
            List<UserNearBy> userNearByList2 = new ArrayList<>();
            for (UserNearBy userNearBy : userNearByList){
                long tid = userNearBy.getUserId();
                if(scoreList1.contains(tid)){
                    userNearByList1.add(userNearBy);
                }else if(scoreList2.contains(tid)){
                    userNearByList2.add(userNearBy);
                }else {

                }
            }

            Collections.sort(userNearByList1);
            Collections.sort(userNearByList2);

            List<UserNearBy> resultList = new ArrayList<>();
            resultList.addAll(userNearByList1);
            resultList.addAll(userNearByList2);

            String key = RedisKeys.SEARCH_USER_NEARBY + Long.toString(userId);
            if(redisUtil.exists(key)){
                redisUtil.remove(key);
            }
            redisUtil.set(key,resultList);
        }

        List<UserNearBy> result = redisUtil.get(RedisKeys.SEARCH_USER_NEARBY + Long.toString(userId));

        long start = page * number > result.size() ? result.size() : page * number ;
        long end = page * number + number > result.size() ? result.size() : page * number + number ;

        List<UserNearBy> response = new ArrayList<>();
        for (long i = start; i < end; i ++){
            UserNearBy userNearBy = result.get((int)i);
            response.add(userNearBy);
            logger.info("userId : " + userNearBy.getUserId() + "     distance : " + userNearBy.getDistance());
        }

        if(response.size() == 0 && page == 0){
            return responseService.doResponse(214);
        }else if(response.size() == 0 && page != 0){
            return responseService.doResponse(216);
        }else {
            RetStatus retStatus = new RetStatus();
            retStatus.setCode(100)
                    .setMessage(RetCode.getMessage(100))
                    .setBody(response);
            return retStatus;
        }
    }

}
